package clock.socoolby.com.clock.widget.animatorview.animator.textanimator;


import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.os.Build;
import android.util.Log;
import android.util.SparseArray;
import java.util.ArrayList;

import clock.socoolby.com.clock.widget.animatorview.AbstractAnimator;
import clock.socoolby.com.clock.widget.animatorview.I_AnimatorEntry;

//引用
public class PathEffectTextAnimator extends AbstractAnimator<PathEffectTextAnimator.PathEffectText> {

    private static final String TAG=PathEffectTextAnimator.class.getSimpleName();
    private static final float BASE_SQUARE_UNIT = 72f;

    public PathEffectTextAnimator() {
        super(1);
    }

    @Override
    public int dialyTime() {
        return 10;
    }

    @Override
    public PathEffectText createNewEntry() {
        return new PathEffectText("TEST");
    }

    public class PathEffectText implements I_AnimatorEntry {

        private String mText = "FUCK";
        private ArrayList<float[]> mDatas;
        private ArrayList<Path> mPaths = new ArrayList<Path>();
        private Paint mPathPaint = new Paint();
        private final Object mSvgLock = new Object();
        private float mPhase=0;
        private Type mType = Type.SINGLE;
        private float mScaleFactor = 1.0f;

        private int mTextColor = Color.BLACK;
        private float mTextSize = BASE_SQUARE_UNIT;
        private float mTextWeight = 20;
        private float mShadowDy = 0;

        public PathEffectText(String mText) {
            mPathPaint.setStyle(Paint.Style.STROKE);
            mPathPaint.setColor(mTextColor);
            mPathPaint.setStrokeWidth(mTextWeight);
            /**
             *  refer to http://stackoverflow.com/questions/27926105/android-paint-setshadowlayer-ignoring-shadowcolor
             *
             *  The shadowLayer works only it the hardware acceleration is disabled
             */

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
                //setLayerType(LAYER_TYPE_SOFTWARE, mPathPaint);
            }
            init(mText);
            setTextSize(200);
        }

        public void setTextColor(int color) {
            mTextColor = color;
            mPathPaint.setColor(color);
        }

        public void setTextWeight(int weight) {
            mTextWeight = weight;
            mPathPaint.setStrokeWidth(mTextWeight);
        }

        public void setTextSize(float size) {
            mTextSize = size;
            mScaleFactor = mTextSize / BASE_SQUARE_UNIT;
        }

        public void setPaintType(Type type) {
            mType = type;
        }


        /**
         * This draws a shadow layer below the main layer, with the specified
         * offset and color, and blur radius. If radius is 0, then the shadow
         * layer is removed.
         * <p/>
         * Can be used to create a blurred shadow underneath text. Support for use
         * with other drawing operations is constrained to the software rendering
         * pipeline.
         * <p/>
         * The alpha of the shadow will be the paint's alpha if the shadow color is
         * opaque, or the alpha from the shadow color if not.
         */
        public void setShadow(int radius, int dx, int dy, int color) {
           // mPathPaint.clearShadowLayer();
            mShadowDy = dy;
            mPathPaint.setShadowLayer(radius, dx, dy, color);
        }

        public void init(String text) {
            if (text == null || text.length() == 0)
                return;

            mText = text;
            mDatas = MatchPath.getPath(mText);
        }

        @Override
        public void onDraw(Canvas canvas, Paint mPaint) {
            if (mPaths == null)
                return;
            //Log.d(TAG,"paths size:"+mPaths.size()+"\tdatas size:"+mDatas.size());
            //synchronized (mSvgLock) {
                for (int i = 0; i < mPaths.size(); i++)
                    canvas.drawPath(mPaths.get(i), mPathPaint);
            //}
        }


        private void updatePathsPhaseLocked() {
            mPaths.clear();
            float singlefactor = mPhase * mDatas.size();
            for (int i = 0; i < mDatas.size(); i++) {
                Path path = new Path();
                path.moveTo(mDatas.get(i)[0] * mScaleFactor + mTextWeight, mDatas.get(i)[1] * mScaleFactor + mTextWeight);
                path.lineTo(mDatas.get(i)[2] * mScaleFactor + mTextWeight, mDatas.get(i)[3] * mScaleFactor + mTextWeight);

                if (mType == Type.MULTIPLY) {
                    PathMeasure measure = new PathMeasure(path, false);
                    Path dst = new Path();
                    measure.getSegment(0.0f, mPhase * measure.getLength(), dst, true);
                    mPaths.add(dst);
                } else {
                    //Fuck! can't compare float and int
                    //Sometimes, at the end of animation , the value is  -9.5176697E-4 or other tiny value.
                    if (singlefactor - (i + 1) >= -0.01)
                        mPaths.add(path);
                    else if (i - Math.floor(singlefactor) < 0.0001) {
                        Path dst = new Path();
                        PathMeasure measure = new PathMeasure(path, false);
                        measure.getSegment(0.0f, (singlefactor % 1) * measure.getLength(), dst, true);
                        mPaths.add(dst);
                    }
                }

            }
        }

        public float getPhase() {
            return mPhase;
        }

        public void setPhase(float phase) {
            mPhase = phase;
            //synchronized (mSvgLock) {
                updatePathsPhaseLocked();
            //}
        }


        @Override
        public void move(int maxWidth, int maxHight) {
            mPhase=mPhase+0.1f;
            if(mPhase>1)
                mPhase=0;
            setPhase(mPhase);
        }

    }

    /**
     * This code comes from https://github.com/liaohuqiu/android-Ultra-Pull-To-Refresh/
     */
    public static class MatchPath {

        private static final SparseArray<float[]> sPointList;

        public static final char V_LEFT = '#';
        public static final char H_TOP_BOTTOM = '$';
        public static final char V_RIGHT = '%';


        static {
            sPointList = new SparseArray<float[]>();
            float[][] LETTERS = new float[][]{
                    new float[]{
                            // A
                            24, 0, 1, 22,
                            1, 22, 1, 72,
                            24, 0, 47, 22,
                            47, 22, 47, 72,
                            1, 48, 47, 48
                    },

                    new float[]{
                            // B
                            0, 0, 0, 72,
                            0, 0, 37, 0,
                            37, 0, 47, 11,
                            47, 11, 47, 26,
                            47, 26, 38, 36,
                            38, 36, 0, 36,
                            38, 36, 47, 46,
                            47, 46, 47, 61,
                            47, 61, 38, 71,
                            37, 72, 0, 72,
                    },

                    new float[]{
                            // C
                            47, 0, 0, 0,
                            0, 0, 0, 72,
                            0, 72, 47, 72,
                    },

                    new float[]{
                            // D
                            0, 0, 0, 72,
                            0, 0, 24, 0,
                            24, 0, 47, 22,
                            47, 22, 47, 48,
                            47, 48, 23, 72,
                            23, 72, 0, 72,
                    },

                    new float[]{
                            // E
                            0, 0, 0, 72,
                            0, 0, 47, 0,
                            0, 36, 37, 36,
                            0, 72, 47, 72,
                    },

                    new float[]{
                            // F
                            0, 0, 0, 72,
                            0, 0, 47, 0,
                            0, 36, 37, 36,
                    },

                    new float[]{
                            // G
                            47, 23, 47, 0,
                            47, 0, 0, 0,
                            0, 0, 0, 72,
                            0, 72, 47, 72,
                            47, 72, 47, 48,
                            47, 48, 24, 48,
                    },

                    new float[]{
                            // H
                            0, 0, 0, 72,
                            0, 36, 47, 36,
                            47, 0, 47, 72,
                    },

                    new float[]{
                            // I
                            0, 0, 47, 0,
                            24, 0, 24, 72,
                            0, 72, 47, 72,
                    },

                    new float[]{
                            // J
                            47, 0, 47, 72,
                            47, 72, 24, 72,
                            24, 72, 0, 48,
                    },

                    new float[]{
                            // K
                            0, 0, 0, 72,
                            47, 0, 3, 33,
                            3, 38, 47, 72,
                    },

                    new float[]{
                            // L
                            0, 0, 0, 72,
                            0, 72, 47, 72,
                    },

                    new float[]{
                            // M
                            0, 0, 0, 72,
                            0, 0, 24, 23,
                            24, 23, 47, 0,
                            47, 0, 47, 72,
                    },

                    new float[]{
                            // N
                            0, 0, 0, 72,
                            0, 0, 47, 72,
                            47, 72, 47, 0,
                    },

                    new float[]{
                            // O
                            0, 0, 0, 72,
                            0, 72, 47, 72,
                            47, 72, 47, 0,
                            47, 0, 0, 0,
                    },

                    new float[]{
                            // P
                            0, 0, 0, 72,
                            0, 0, 47, 0,
                            47, 0, 47, 36,
                            47, 36, 0, 36,
                    },

                    new float[]{
                            // Q
                            0, 0, 0, 72,
                            0, 72, 23, 72,
                            23, 72, 47, 48,
                            47, 48, 47, 0,
                            47, 0, 0, 0,
                            24, 28, 47, 71,
                    },

                    new float[]{
                            // R
                            0, 0, 0, 72,
                            0, 0, 47, 0,
                            47, 0, 47, 36,
                            47, 36, 0, 36,
                            0, 37, 47, 72,
                    },

                    new float[]{
                            // S
                            47, 0, 0, 0,
                            0, 0, 0, 36,
                            0, 36, 47, 36,
                            47, 36, 47, 72,
                            47, 72, 0, 72,
                    },

                    new float[]{
                            // T
                            0, 0, 47, 0,
                            24, 0, 24, 72,
                    },

                    new float[]{
                            // U
                            0, 0, 0, 72,
                            0, 72, 47, 72,
                            47, 72, 47, 0,
                    },

                    new float[]{
                            // V
                            0, 0, 24, 72,
                            24, 72, 47, 0,
                    },

                    new float[]{
                            // W
                            0, 0, 0, 72,
                            0, 72, 24, 49,
                            24, 49, 47, 72,
                            47, 72, 47, 0
                    },

                    new float[]{
                            // X
                            0, 0, 47, 72,
                            47, 0, 0, 72
                    },

                    new float[]{
                            // Y
                            0, 0, 24, 23,
                            47, 0, 24, 23,
                            24, 23, 24, 72
                    },

                    new float[]{
                            // Z
                            0, 0, 47, 0,
                            47, 0, 0, 72,
                            0, 72, 47, 72
                    },
            };
            final float[][] NUMBERS = new float[][]{
                    new float[]{
                            // 0
                            0, 0, 0, 72,
                            0, 72, 47, 72,
                            47, 72, 47, 0,
                            47, 0, 0, 0,
                    },
                    new float[]{
                            // 1
                            24, 0, 24, 72,
                    },

                    new float[]{
                            // 2
                            0, 0, 47, 0,
                            47, 0, 47, 36,
                            47, 36, 0, 36,
                            0, 36, 0, 72,
                            0, 72, 47, 72
                    },

                    new float[]{
                            // 3
                            0, 0, 47, 0,
                            47, 0, 47, 36,
                            47, 36, 0, 36,
                            47, 36, 47, 72,
                            47, 72, 0, 72,
                    },

                    new float[]{
                            // 4
                            0, 0, 0, 36,
                            0, 36, 47, 36,
                            47, 0, 47, 72,
                    },

                    new float[]{
                            // 5
                            0, 0, 0, 36,
                            0, 36, 47, 36,
                            47, 36, 47, 72,
                            47, 72, 0, 72,
                            0, 0, 47, 0
                    },

                    new float[]{
                            // 6
                            0, 0, 0, 72,
                            0, 72, 47, 72,
                            47, 72, 47, 36,
                            47, 36, 0, 36
                    },

                    new float[]{
                            // 7
                            0, 0, 47, 0,
                            47, 0, 47, 72
                    },

                    new float[]{
                            // 8
                            0, 0, 0, 72,
                            0, 72, 47, 72,
                            47, 72, 47, 0,
                            47, 0, 0, 0,
                            0, 36, 47, 36
                    },

                    new float[]{
                            // 9
                            47, 0, 0, 0,
                            0, 0, 0, 36,
                            0, 36, 47, 36,
                            47, 0, 47, 72,
                    }
            };
            // A - Z
            for (int i = 0; i < LETTERS.length; i++) {
                sPointList.append(i + 65, LETTERS[i]);
            }
            // a - z
            for (int i = 0; i < LETTERS.length; i++) {
                sPointList.append(i + 65 + 32, LETTERS[i]);
            }
            // 0 - 9
            for (int i = 0; i < NUMBERS.length; i++) {
                sPointList.append(i + 48, NUMBERS[i]);
            }
            // blank
            addChar(' ', new float[]{});
            // -
            addChar('-', new float[]{
                    0, 36, 47, 36
            });
            // .
            addChar('.', new float[]{
                    24, 60, 24, 72
            });

            //
            addChar(V_LEFT, new float[]{
                    -12, 120, -12, 38,
                    -12, 38, -12, -45
            });
            //
            addChar(H_TOP_BOTTOM, new float[]{
                    0, -45, 23, -45,
                    23, -45, 67, -45,
                    0, 120, 23, 120,
                    23, 120, 67, 120
            });

            //
            addChar(V_RIGHT, new float[]{
                    79, -45, 79, 38,
                    79, 38, 79, 120
            });
        }

        public static void addChar(char c, float[] points) {
            sPointList.append(c, points);
        }

        public static ArrayList<float[]> getPath(String str) {
            return getPath(str, 1, 14);
        }

        public static boolean isButtonModle;

        /**
         * @param str
         * @param scale
         * @param gapBetweenLetter
         * @return ArrayList of float[] {x1, y1, x2, y2}
         */
        public static ArrayList<float[]> getPath(String str, float scale, int gapBetweenLetter) {
            ArrayList<float[]> list = new ArrayList<float[]>();
            float offsetForWidth = 0;
            for (int i = 0; i < str.length(); i++) {
                int pos = str.charAt(i);
                int key = sPointList.indexOfKey(pos);
                if (key == -1) {
                    continue;
                }
                float[] points = sPointList.get(pos);

                if (isButtonModle) {
                    float[] points1 = new float[points.length + 16];
                    for (int j = 0; j < sPointList.get(H_TOP_BOTTOM).length; j++) {
                        points1[j] = sPointList.get(H_TOP_BOTTOM)[j];
                    }
                    for (int j = 0; j < points.length; j++) {
                        points1[j + 16] = points[j];
                    }
                    points = points1;
                }

                int pointCount = points.length / 4;
                for (int j = 0; j < pointCount; j++) {
                    float[] line = new float[4];
                    for (int k = 0; k < 4; k++) {
                        float l = points[j * 4 + k];
                        // x
                        if (k % 2 == 0) {
                            line[k] = (l + offsetForWidth) * scale;
                        }
                        // y
                        else {
                            line[k] = l * scale;
                        }
                    }
                    list.add(line);
                }
                offsetForWidth += 57 + gapBetweenLetter;
            }

            if (isButtonModle) {
                isButtonModle = false;
            }
            return list;
        }
    }

    public enum Type {
        SINGLE, MULTIPLY
    }
}
